import ffmpeg
import os
import sys


# --- 通用函数 ---
def run_ffmpeg_process(stream, output_path):
    """
    执行 FFmpeg 命令，并处理输出。
    stream: ffmpeg-python 的流对象
    output_path: 输出文件路径
    """
    # 如果输出文件已存在，先删除
    if os.path.exists(output_path):
        os.remove(output_path)

    print("===================================================")
    print(f"即将执行的 FFmpeg 命令: {' '.join(ffmpeg.compile(stream))}")
    print("===================================================")

    try:
        # .run() 会阻塞直到 FFmpeg 进程完成
        # capture_stdout=True 和 capture_stderr=True 可以捕获输出，用于日志记录
        out, err = stream.run(capture_stdout=True, capture_stderr=True, overwrite_output=True)
        print(f"处理成功! 文件已保存到: {output_path}")
        # print("FFmpeg stdout:", out.decode('utf-8'))
        if err:
            print("FFmpeg stderr:", err.decode('utf-8'))
    except ffmpeg.Error as e:
        print("处理失败，发生错误。")
        print("FFmpeg stderr:", e.stderr.decode('utf-8'))
        sys.exit(1)


def get_video_info(video_path):
    """
    获取视频的基本信息：时长、分辨率、帧率、码率、编码格式等
    :param video_path: 视频文件路径
    :return: 包含视频信息的字典
    """
    try:

        probe = ffmpeg.probe(video_path)
        video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'videotemplate'), None)

        if video_stream is None:
            print("错误：未找到视频流")
            return None

        info = {
            'duration': float(probe['format']['duration']),  # 时长（秒）
            'width': int(video_stream['width']),
            'height': int(video_stream['height']),
            'fps': eval(video_stream['r_frame_rate']),  # 帧率（如 30/1 → 30.0）
            'bitrate': int(probe['format'].get('bit_rate', 0)),  # 码率（bps）
            'codec': video_stream['codec_name'],  # 编码器名称
        }

        return info

    except ffmpeg.Error as e:
        print("FFmpeg 错误:", e.stderr.decode())
        return None


# ==============================================================================
# 1. 视频截取 (Trimming Video)
# 从视频的第10秒截取到第15秒
# ==============================================================================
def trim_video(input_path, output_path, start_time, end_time):
    """
    截取视频并使用 libx264 + aac 编码输出
    :param input_path: 输入视频路径
    :param output_path: 输出视频路径
    :param start_time: 开始时间 (秒)
    :param end_time: 结束时间 (秒)
    """
    print("\n[功能1: 视频截取]")

    if start_time >= end_time:
        print("错误：结束时间必须大于开始时间。")
        return

    duration = end_time - start_time

    stream = ffmpeg.input(input_path)

    output_stream = (
        ffmpeg.output(
            stream,
            output_path,
            ss=start_time,
            t=duration,
            vcodec='libx264',
            acodec='aac'
        )
        .global_args('-y')  # 覆盖输出文件
    )

    run_ffmpeg_process(output_stream, output_path)


# ==============================================================================
# 2. 分离视频和音频 (Separate Video and Audio)
# ==============================================================================
def separate_media(input_path, video_output_path, audio_output_path):
    """
    分离视频流和音频流
    """
    print("\n[功能2: 分离视频和音频]")
    input_stream = ffmpeg.input(input_path)

    # 提取视频流 (-vn: no audio)
    print("--> 正在分离视频流...")
    video_stream = ffmpeg.output(input_stream.video, video_output_path, vcodec='copy', an=None)
    run_ffmpeg_process(video_stream, video_output_path)

    # 提取音频流 (-an: no videotemplate)
    print("--> 正在分离音频流...")
    audio_stream = ffmpeg.output(input_stream.audio, audio_output_path, acodec='copy', vn=None)
    run_ffmpeg_process(audio_stream, audio_output_path)


# ==============================================================================
# 3. 合并视频和音频 (Merge Video and Audio)
# ==============================================================================
def merge_media(video_input_path, audio_input_path, output_path):
    """
    合并独立的视频流和音频流
    """
    print("\n[功能3: 合并视频和音频]")
    video_stream = ffmpeg.input(video_input_path)
    audio_stream = ffmpeg.input(audio_input_path)

    # -c:v copy 表示视频流直接复制，不重新编码
    # -c:a copy 表示音频流直接复制，不重新编码
    # -shortest 表示输出文件的时长以最短的输入流为准
    merged_stream = ffmpeg.output(video_stream, audio_stream, output_path, vcodec='copy', acodec='copy', shortest=None)
    run_ffmpeg_process(merged_stream, output_path)


# ==============================================================================
# 4. 添加硬字幕 (Add Hard Subtitles)
# "硬字幕"是指将字幕像素直接绘制到视频帧上，成为视频的一部分。
# ==============================================================================
def add_hard_subtitles(input_path, subtitle_path, output_path):
    """
    为视频添加硬字幕
    """
    print("\n[功能4: 添加硬字幕]")
    # 确保字幕文件路径对于 ffmpeg 是安全的
    # 在 Windows 上，路径可能需要特殊处理
    if sys.platform == 'win32':
        subtitle_path = subtitle_path.replace('\\', '/')

    stream = ffmpeg.input(input_path)
    # 使用 `subtitles` 视频滤镜 (vf)
    # 注意: 字幕文件的路径对于 FFmpeg 进程必须是可访问的
    output_stream = ffmpeg.output(stream, output_path, vf=f"subtitles='{subtitle_path}'")
    run_ffmpeg_process(output_stream, output_path)


# ==============================================================================
# 5. 添加图片水印 (Add Image Watermark)
# ==============================================================================
def add_watermark(input_path, logo_path, output_path, position="10:10"):
    """
    为视频添加图片水印
    :param position: 水印位置，格式为 "x:y"。例如 "10:10" 是左上角, "main_w-overlay_w-10:10" 是右上角
    """
    print("\n[功能5: 添加图片水印]")
    main_video = ffmpeg.input(input_path)
    watermark_logo = ffmpeg.input(logo_path)

    # 使用 `overlay` 滤镜
    # main_w, main_h: 主视频的宽和高
    # overlay_w, overlay_h: 水印图片的宽和高
    stream = ffmpeg.overlay(main_video, watermark_logo, x=position.split(':')[0], y=position.split(':')[1])
    output_stream = ffmpeg.output(stream, output_path)
    run_ffmpeg_process(output_stream, output_path)


# ==============================================================================
# 6. 读取视频关键帧 (Extract Keyframes)
# ==============================================================================
def extract_keyframes(input_path, output_folder):
    """
    提取视频的所有I帧（关键帧）并保存为图片
    """
    print("\n[功能6: 读取视频关键帧]")
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    # 使用 select 滤镜选择I帧 (I-frames)
    # -vsync vfr 确保帧率与源匹配，防止重复帧
    # aselect='eq(pict_type,I)'
    stream = ffmpeg.input(input_path)
    output_filename = os.path.join(output_folder, 'keyframe_%03d.jpg')

    output_stream = ffmpeg.output(stream, output_filename, vf="select='eq(pict_type,I)'", vsync='vfr',
                                  **{'q:v': 2})  # q:v 2 代表高质量JPG
    run_ffmpeg_process(output_stream, output_filename)


def extract_specific_frame(input_path, output_path, time_in_seconds):
    """
    提取指定时间的单帧画面
    """
    print(f"\n[功能6.1: 提取指定时间 {time_in_seconds}s 的帧]")
    stream = ffmpeg.input(input_path, ss=time_in_seconds)
    # -vframes 1 表示只输出一帧
    output_stream = ffmpeg.output(stream, output_path, vframes=1)
    run_ffmpeg_process(output_stream, output_path)


# ==============================================================================
# 7. 视频拼接 (Concatenate Videos)
# ==============================================================================
def concat_videos(input_paths, output_path):
    """
    将多个视频文件拼接为一个完整视频
    :param input_paths: 输入视频路径列表，如 ["video1.mp4", "video2.mp4"]
    :param output_path: 输出视频路径
    """
    print("\n[功能7: 视频拼接]")

    if len(input_paths) < 2:
        print("错误：至少需要两个视频进行拼接")
        return

    try:
        # 创建输入流列表
        streams = [ffmpeg.input(p) for p in input_paths]

        # 使用 concat 滤镜拼接所有视频流和音频流
        joined_stream = ffmpeg.concat(*streams, v=1, a=1).node

        # 输出拼接后的视频
        output_stream = ffmpeg.output(joined_stream[0], joined_stream[1], output_path, vcodec='libx264', acodec='aac')

        run_ffmpeg_process(output_stream, output_path)

    except Exception as e:
        print("拼接失败:", str(e))


def concat_videos_with_filelist(input_list_path, output_path):
    """
    使用文件列表进行视频拼接
    :param input_list_path: 包含视频文件路径的文本文件（每行一个视频）
    :param output_path: 输出视频路径
    """
    print("\n[功能7.1: 使用文件列表拼接视频]")

    if not os.path.exists(input_list_path):
        print(f"错误：文件列表 '{input_list_path}' 不存在。")
        return

    try:
        # 使用 ffconcat 协议读取文件列表
        stream = ffmpeg.input(input_list_path, format='concat', safe=0)
        output_stream = ffmpeg.output(stream, output_path, c='copy')
        run_ffmpeg_process(output_stream, output_path)

    except Exception as e:
        print("拼接失败:", str(e))


# --- 主执行逻辑 ---
if __name__ == '__main__':
    # --- 定义输入文件 ---
    input_file = '../file/dev.mp4'
    # 确保输入文件存在
    if not os.path.exists(input_file):
        print(f"错误: 输入文件 '{input_file}' 不存在。请准备一个视频文件。")
        sys.exit(1)

    # 0.获取视频基本信息
    print('视频相关信息：', get_video_info(input_file))

    # 1. 视频截取
    trim_video(input_file, 'output_trimmed.mp4', start_time=10, end_time=15)

    # 2. 分离视频和音频
    separate_media(input_file, 'output_only_video.mp4', 'output_only_audio.m4a')

    # 3. 合并视频和音频
    # 检查上一步生成的文件是否存在
    if os.path.exists('output_only_video.mp4') and os.path.exists('output_only_audio.m4a'):
        merge_media('output_only_video.mp4', 'output_only_audio.m4a', 'output_merged.mp4')
    else:
        print("\n跳过合并测试，因为分离出的音视频文件不存在。")

    # 4. 添加硬字幕
    if os.path.exists('../controller/output.srt'):
        add_hard_subtitles(input_file, '../controller/output.srt', 'output_subtitled.mp4')
    else:
        print("\n跳过添加字幕测试，因为 'subtitle.srt' 文件不存在。")

    # 5. 添加水印
    if os.path.exists('../file/logo.png'):
        # 左上角水印
        add_watermark(input_file, '../file/logo.png', 'output_watermarked.mp4', position="10:10")
        # 右下角水印
        # add_watermark(input_file, 'logo_bak.png', 'output_watermarked_br.mp4', position="main_w-overlay_w-10:main_h-overlay_h-10")
    else:
        print("\n跳过添加水印测试，因为 'logo_bak.png' 文件不存在。")

    # 6. 提取帧
    extract_keyframes(input_file, 'keyframes_output')
    extract_specific_frame(input_file, 'frame_at_10s.jpg', 10)

    print("\n所有任务已执行完毕！")
